home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
C
/
Applications
/
GW AdaEd 1.4.2
/
GWAdaDemos
/
GWU Demos
/
elevator.gen
< prev
next >
Wrap
Text File
|
1995-04-09
|
13KB
|
346 lines
-- Simple Elevator Simulation Program
--
-- By Arthur V. Lopes - (C) 1993
-- Package (generic): Elevator_Simulation
GENERIC
No_Elevators : Natural;
Elevator_Capacity : Natural;
No_Floors : Natural;
No_Passengers : Natural;
PACKAGE Elevator_Simulation IS
SUBTYPE Floor_Type IS Integer RANGE 1..No_Floors;
SUBTYPE Elevator_Type IS Integer RANGE 1..No_Elevators;
SUBTYPE Passenger_Type IS Integer RANGE 1..No_Passengers;
SUBTYPE Capacity_Type IS Integer RANGE 0..Elevator_Capacity;
-- SUBTYPE Screen_Depth IS Integer RANGE 1..24; -- See package screen
-- SUBTYPE Screen_Width IS Integer RANGE 1..80;
TYPE State IS (Going_Up, Going_Down, Neutral, In_Maintenance);
TYPE Passenger_Waiting IS RECORD
Id : Passenger_Type;
Where : Floor_Type;
Go_To : Floor_Type;
Time_In : Natural;
Direction : State;
END RECORD;
TASK Generate_Passengers IS
ENTRY Start;
END Generate_Passengers;
TASK TYPE Elevator_Task_Type IS
ENTRY Turn_Key_On(Elevator_Id : Elevator_Type);
END Elevator_Task_Type;
TASK Control IS
ENTRY Start;
ENTRY Open_Doors_Building;
ENTRY Get_New_Passenger(Passenger : Passenger_Waiting);
ENTRY At_Floor(Floor_No : Floor_Type;
Unit : Elevator_Type;
Going : State);
ENTRY Shut_Down;
END Control;
Elevator : ARRAY(Elevator_Type) OF Elevator_Task_Type;
Total_Wait_Time : Natural := 0;
END Elevator_Simulation;
WITH Screen_IO; USE Screen_IO;
WITH Random; USE Random;
WITH Text_IO; USE Text_IO;
WITH My_Int_IO; USE My_Int_IO;
WITH Calendar; USE Calendar;
PACKAGE BODY Elevator_Simulation IS
Passenger_Load : CONSTANT := 32;
Passengers_To_Go : Natural := No_Passengers;
Load : ARRAY(Elevator'RANGE) OF Capacity_Type := (OTHERS => 0);
Stops : ARRAY(Elevator'RANGE,1..No_Floors) OF Natural;
Activity : ARRAY(Elevator'RANGE) OF State := (OTHERS => Neutral);
Waiting : ARRAY(1..No_Passengers) OF Passenger_Waiting;
No_Waiting: Natural := 0;
In_Unit : ARRAY(Elevator'RANGE,1..Elevator_Capacity) OF Passenger_Waiting;
No_In_Unit : ARRAY(Elevator'RANGE) OF Natural := (OTHERS => 0);
FUNCTION Tell_Me_Where_I_Am RETURN Floor_Type IS
BEGIN
RETURN Random_Int(Floor_Type'LAST);
END;
FUNCTION Floor_To_Go(From_Floor : Floor_Type) RETURN Floor_Type IS
Temp : Floor_Type;
BEGIN
Temp := Random_Int(Floor_Type'LAST);
WHILE Temp = From_Floor LOOP
Temp := Random_Int(Floor_Type'LAST);
END LOOP;
RETURN Temp;
END;
TASK BODY Generate_Passengers IS
I : Natural := 0;
One : Passenger_Waiting;
BEGIN
ACCEPT Start;
While I < No_Passengers LOOP
IF (Random_Int(181) MOD 2) = 0 THEN
I := I + 1;
One.Id := I;
One.Where := Tell_Me_Where_I_Am;
One.Go_To := Floor_To_Go(One.Where);
IF One.Where > One.Go_To THEN
One.Direction := Going_Down;
ELSE
One.Direction := Going_Up;
END IF;
One.Time_In := Natural( Seconds (Clock));
Control.Get_New_Passenger(One);
END IF;
END LOOP;
END Generate_Passengers;
TASK BODY Elevator_Task_Type IS
Old_Activity : State := Neutral;
My_Id : Elevator_Type;
Current_Floor : Natural := 1;
Old_Where : Floor_Type := Floor_Type'FIRST;
Stoped : Boolean;
PROCEDURE Move IS
BEGIN
CASE Activity(My_Id) IS
WHEN Going_Up =>
Current_Floor := Current_Floor + 1;
IF Current_Floor > No_Floors THEN
Current_Floor := No_Floors;
Activity(My_Id) := Going_Down;
ELSE
DELAY 0.1; -- Time to reach this floor
END IF;
WHEN Going_Down =>
Current_Floor := Current_Floor - 1;
IF Current_Floor < 1 THEN
Current_Floor := 1;
Activity(My_Id) := Going_Up;
ELSE
DELAY 0.1; -- Time to reach this floor
END IF;
WHEN Neutral =>
Activity(My_Id) := Going_Up;
WHEN In_Maintenance =>
Delay 100.0;
WHEN OTHERS =>
NULL;
END CASE;
FOR J IN 1..No_Floors LOOP
Terminal.WriteAt(Where => (My_ID + 5, J * 2 + 14), What => " ");
END LOOP;
Terminal.WriteAt(Where => (My_Id + 5, Current_Floor * 2 + 14),
What => Integer'IMAGE(Load(My_Id)));
END Move;
BEGIN
ACCEPT Turn_Key_On(Elevator_Id : Elevator_Type) DO
My_Id := Elevator_Id;
END Turn_Key_On;
Terminal.WriteAt(Where => (My_Id + 5, 1),
What => "Elevator " & Integer'IMAGE(My_Id));
--Screen_Mgm.Msg(My_Id + 5, 1,"Elevator " & Integer'IMAGE(My_Id));
LOOP
IF Passengers_To_Go <= 0 THEN
EXIT;
END IF;
Terminal.WriteAt(Where => (My_Id + 5, Old_where * 2 + 14),
What => " ");
Terminal.WriteAt(Where => (My_Id + 5, Current_Floor * 2 + 14),
What => Integer'IMAGE(Load(My_Id)));
Stoped := False;
IF No_In_Unit(My_Id) > 0 AND Passengers_To_Go > 0 THEN
FOR I IN 1..No_In_Unit(My_Id) LOOP
IF In_Unit(My_Id,I).Go_To = Current_FLoor THEN
-- Allow passengers to get in / out; Control unit
Control.At_Floor(Current_Floor,My_Id,Activity(My_Id));
Stoped := True;
EXIT;
END IF;
END LOOP;
END IF;
IF NOT Stoped THEN
IF Stops(My_Id,Current_Floor) > 0 AND
No_In_Unit(My_Id) < Elevator_Capacity THEN
Control.At_Floor(Current_Floor,My_Id,Activity(My_Id));
END IF;
END IF;
Move;
IF Activity(My_Id) /= Old_Activity THEN
Old_Activity := Activity(My_Id);
DELAY 0.2; -- Accelaration / Dessacelaration factor
END IF;
Old_Where := Current_Floor;
END LOOP;
END Elevator_Task_Type;
TASK BODY Control IS
From_Elevator : Elevator_Type;
From_Floor : Floor_Type;
Unit : Elevator_Type;
Last_Unit : Elevator_Type := Elevator'FIRST;
I : Natural;
FUNCTION Best_Unit(Current_Floor : Floor_Type) RETURN Elevator_Type IS
BU : Elevator_Type := 1;
DBU : Natural := 0;
D : Natural;
BEGIN
-- For now just do a circular assignment
IF Last_Unit = Elevator'LAST THEN
Last_Unit := Elevator'FIRST;
ELSE
Last_Unit := Last_Unit + 1;
END IF;
RETURN Last_Unit;
END Best_Unit;
BEGIN
ACCEPT Start;
FOR I IN Elevator'RANGE LOOP
FOR J IN 1..No_Floors LOOP
Stops(I,J) := 0; -- Clear stops
END LOOP;
Elevator(I).Turn_Key_On(I);
END LOOP;
ACCEPT Open_Doors_Building;
Generate_Passengers.Start;
LOOP
IF Passengers_To_Go <= 0 THEN
EXIT;
END IF;
SELECT
WHEN No_Waiting < Passenger_Load =>
ACCEPT Get_New_Passenger(Passenger : Passenger_Waiting) DO
No_Waiting := No_Waiting + 1;
Waiting(No_Waiting) := Passenger;
Unit := Best_Unit(Waiting(No_Waiting).Where);
Stops(Unit,Waiting(No_Waiting).Where) :=
Stops(Unit,Waiting(No_Waiting).Where) + 1;
Terminal.WriteAt(Where => (2, Passenger.Id * 2 + 14),
What => Integer'IMAGE(Passenger.Where));
Terminal.WriteAt(Where => (3, Passenger.Id * 2 + 14),
What => Integer'IMAGE(Passenger.Go_To));
Terminal.WriteAt(Where => (4, Passenger.Id * 2 + 14),
What => " ");
END Get_New_Passenger;
OR
ACCEPT At_Floor(Floor_No : Floor_Type;
Unit : Elevator_Type;
Going : State) DO
-- Allow passengers to get out
I := 1;
WHILE I <= No_In_Unit(Unit) LOOP
IF In_Unit(Unit,I).Go_To = Floor_No THEN
Total_Wait_Time := Total_Wait_Time +
Natural ( Seconds (Clock)) -
In_Unit(Unit,I).Time_In;
Terminal.WriteAt(Where => (4, In_Unit(Unit,I).Id * 2 + 14),
What => " *");
-- Put passenger outside elevator
FOR J IN I..No_In_Unit(Unit) - 1 LOOP
In_Unit(Unit,J) := In_Unit(Unit,J + 1);
END LOOP;
No_In_Unit(Unit) := No_In_Unit(Unit) - 1;
IF Load(Unit) > 0 THEN
Load(Unit) := Load(Unit) - 1;
END IF;
FOR J IN 1..No_Floors LOOP
Terminal.WriteAt(Where => (Unit + 5, J * 2 + 14),
What => " ");
END LOOP;
Terminal.WriteAt(Where => (Unit + 5, Floor_No * 2 + 14),
What => Integer'IMAGE(No_In_Unit(Unit)));
Passengers_To_Go := Passengers_To_Go - 1;
ELSE
I := I + 1;
END IF;
END LOOP;
-- Now allow passengers to get in
I := 1;
WHILE I <= No_Waiting LOOP
IF Waiting(I).Where = Floor_No THEN
IF No_In_Unit(Unit) < Elevator_Capacity THEN
-- AND Going = Waiting(I).Direction THEN
-- Put passenger inside elevator
No_In_Unit(Unit) := No_In_Unit(Unit) + 1;
In_Unit(Unit,No_In_Unit(Unit)) := Waiting(I);
IF Stops(Unit,Floor_No) > 0 THEN
Stops(Unit,Floor_No) := Stops(Unit,Floor_No) - 1;
END IF;
Load(Unit) := Load(Unit) + 1;
FOR J IN 1..No_Floors LOOP
Terminal.WriteAt(Where => (Unit + 5, J * 2 + 14),
What => " ");
END LOOP;
Terminal.WriteAt(Where => (Unit + 5, Floor_No * 2 + 14),
What => Integer'IMAGE(Load(Unit)));
FOR J IN I..No_Waiting - 1 LOOP
Waiting(J) := Waiting(J + 1);
END LOOP;
No_Waiting := No_Waiting - 1;
ELSE
I := I + 1;
END IF;
ELSE
I := I + 1;
END IF;
END LOOP;
END At_Floor;
OR
TERMINATE;
END SELECT;
END LOOP;
ACCEPT Shut_Down;
EXCEPTION
WHEN CONSTRAINT_ERROR =>
Terminal.WriteAt(Where => (23,1), What => "Unit=" & Integer'IMAGE(Unit));
Terminal.WriteAt(Where => (23,9),
What => "N_In_U(U)=" & INTEGER'IMAGE(No_In_Unit(Unit)));
Terminal.WriteAt(Where => (24,1),
What => "P G in I=" & Integer'IMAGE(I));
Terminal.WriteAt(Where => (24,15),
What => " No_Waiting=" & Integer'IMAGE(No_Waiting));
FOR J IN 1..No_Waiting LOOP
Terminal.WriteAt(Where => (24,32+J),
What => Integer'IMAGE(Waiting(j).Go_To) & " ");
END LOOP;
END Control;
END Elevator_Simulation;